#include "musicmetadata.h"


MusicMetaData::MusicMetaData() {

}


MusicMetaData::MusicMetaData(QString &filePath, ergodicFlags flag = Current) {
    Open(filePath, flag);
}


void MusicMetaData::Open(QString &filePath, ergodicFlags flag = Current) {
    if (flag == Current)
        ErgodicCurrentFolder(filePath);
    else
        ErgodicAllFolder(filePath);
}


QMap<QString, QString> MusicMetaData::GetBaseInfo(QFileInfo &fileInfo) {
    QMap<QString, QString> musicTags;   // music info

    // file path convert (QString to char*)
    std::string str = fileInfo.absoluteFilePath().toStdString();
    const char *ch = str.c_str();

    AVFormatContext *fmtCtx = NULL; // format I/O context
    AVDictionaryEntry *tag = NULL;  // meta data (key-value)

    av_register_all();  // initialize libavformat and register all the muxers, demuxers and protocols
    if (avformat_open_input(&fmtCtx, ch, NULL, NULL))   // open an input stream and read the header
    {
        musicTags["error"] = QString("yes");
        return musicTags;
    }

    // Read packets of a media file to get stream information
    if (avformat_find_stream_info(fmtCtx, NULL))
    {
        musicTags["error"] = QString("yes");
        return musicTags;
    }

    // get file size
    qint64 fileSize = fileInfo.size() / 1024;
    if (fileSize / 1024)
    {
        fileSize = fileSize * 100 / 1024;
        musicTags["filesize"] = QString::number(fileSize / 100.0) + " MB";
    }
    else
    {
        musicTags["filesize"] = QString::number(fileSize) + "KB";
    }

    musicTags["error"] = QString("no");
    musicTags["filename"] = fileInfo.completeBaseName();
    musicTags["filepath"] = fileInfo.absoluteFilePath();    // file path (including the file name)

    // get a dictionary entry with matching key
    while (tag = av_dict_get(fmtCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))
    {
        if (!QString(tag->key).compare("title") || !QString(tag->key).compare("artist"))
        {
            musicTags[QString(tag->key)] = QString(tag->value);
        }
    }

    // time format
    int all_time = fmtCtx->duration / 1000000;
    int min_time = all_time / 60;
    double sec_time = (all_time - min_time * 60) / 100.0;
    double end_time = min_time + sec_time;

    musicTags["time"] = QString::number(end_time).replace(".", ":");
    musicTags["bitrate"] = QString::number(fmtCtx->bit_rate / 1000);

    avformat_close_input(&fmtCtx); // close an opened input AVFormatContext
    return musicTags;
}


void MusicMetaData::ErgodicCurrentFolder(QString &filePath) {
    QDir dir(filePath);
    if (!dir.exists())
    {
        return;
    }

    // filting files
    QStringList suffixFilter;
    suffixFilter << QString("*.mp3")
                 << QString("*.wav")
                 << QString("*.wma")
                 << QString("*.aac")
                 << QString("*.ogg")
                 << QString("*.ape")
                 << QString("*.flac");

    dir.setFilter(QDir::Files | QDir::NoSymLinks);
    dir.setNameFilters(suffixFilter);
    fileList = dir.entryInfoList();
}


void MusicMetaData::ErgodicAllFolder(QString &filePath) {
    QDir dir(filePath);
    if (!dir.exists())
    {
        return;
    }

    // filting files
    QStringList suffixFilter;
    suffixFilter << QString("*.mp3")
                 << QString("*.wav")
                 << QString("*.wma")
                 << QString("*.aac")
                 << QString("*.ogg")
                 << QString("*.ape")
                 << QString("*.flac");

    QDirIterator dirIterator(filePath, suffixFilter, QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
    while (dirIterator.hasNext())
    {
        dirIterator.next();
        fileList.append(dirIterator.fileInfo());
    }
}


QList<QMap<QString, QString> > MusicMetaData::GetAllBaseInfo() {
    QList<QMap<QString, QString> > baseData;
    for (int i = 0; i != fileList.count(); ++i)
    {
        baseData.append(GetBaseInfo(fileList[i]));
    }

    return baseData;
}

